//
//	File: OyDirect3D9_SkinManager.cpp
//


#include "OyDirect3D9_SkinManager.h"
#include "../OyMath3D/OyMath3D.h"
#include "../OyGeneral/OyGeneral.h"

#include "FreeImage.h"

static char EngineErrorString[256];

// BKDR Hash Function
unsigned long int UnicodeStringHash( UnicodeString p_string )
{
	unsigned long int seed = 131;
    unsigned long int hash = 0;
    int i;
    int length = _tcslen( p_string.m_string );
    for( i = 0; i < length; i++ )
    {
		hash = hash * seed + p_string.m_string[i];
    }

    return (hash & 0x7FFFFFFF);
}


OyD3D9SkinManager::OyD3D9SkinManager(LPDIRECT3DDEVICE9 pDevice) :
	m_TexNameIDMap(MAX_TEXTURE_FILENAME_HASHTABLE_NUM, UnicodeStringHash)
{
	m_nNumMaterials = 0;
	m_nNumTextures  = 0;
	m_nNumSkins     = 0;

	m_Materials.Init(INIT_MATERIAL_ARRAY_NUM);
	m_Textures.Init(INIT_TEXTURE_ARRAY_NUM);
	m_Skins.Init(INIT_SKIN_ARRAY_NUM);

	m_SyncLoadTextureList.Append(new RingFIFO<DLTexture>(INIT_SYNC_TEXTURE_RESOURCE));

	m_pDevice       = pDevice;
}

OyD3D9SkinManager::~OyD3D9SkinManager(void)
{
	// release direct3d texture objects
	for(UINT i=0; i<m_nNumTextures; i++)
	{
		if(m_Textures[i].pData)
		{
			((LPDIRECT3DTEXTURE9)(m_Textures[i].pData))->Release();
			m_Textures[i].pData = NULL;
		}
		if(m_Textures[i].chName)
		{
			delete [] m_Textures[i].chName;
			m_Textures[i].chName = NULL;
		}
	}

	DoubleListIterator<RingFIFO<DLTexture>*> it = m_SyncLoadTextureList.GetIterator();
	while( it.Valid() )
	{
		delete it.Item();
		it.Item() = NULL;
		it.Forth();
	}
}

void OyD3D9SkinManager::Reset(void)
{
	// release direct3d texture objects
	for(UINT i=0; i<m_nNumTextures; i++)
	{
		if(m_Textures[i].pData) 
		{
			((LPDIRECT3DTEXTURE9)(m_Textures[i].pData))->Release();
			m_Textures[i].pData = NULL;
		}

		if(m_Textures[i].chName) 
		{
			delete [] m_Textures[i].chName;
			m_Textures[i].chName = NULL;
		}
	}
   
	// release allocated memory
	m_Materials.~OyArray();
	m_Materials.Init(INIT_MATERIAL_ARRAY_NUM);
	m_Textures.~OyArray();
	m_Textures.Init(INIT_TEXTURE_ARRAY_NUM);
	m_Skins.~OyArray();
	m_Skins.Init(INIT_SKIN_ARRAY_NUM);

	m_nNumMaterials = 0;
	m_nNumTextures  = 0;
	m_nNumSkins     = 0;
}

// Returns a copy of the requested skin object if it exists.
OySkin OyD3D9SkinManager::GetSkin(UINT nSkinID)
{
	if(nSkinID < m_nNumSkins) 
		return m_Skins[nSkinID];
	else 
	{
		OySkin EmptySkin;
		return EmptySkin;
	}
}


// Returns a copy of the requested material object if it exists.
OyMaterial OyD3D9SkinManager::GetMaterial(UINT nMatID)
{
	if(nMatID < m_nNumMaterials)
		return m_Materials[nMatID];
	else
	{
		OyMaterial EmptyMaterial;
		return EmptyMaterial;
	}
}

// Returns the requested texture name about the texture object
const TCHAR* OyD3D9SkinManager::GetTextureName(UINT TexID)
{
	if(TexID >= m_nNumTextures) 
		return NULL;

	return m_Textures[TexID].chName;
}

const void* OyD3D9SkinManager::GetOyTextureData(UINT TexID)
{
	if(TexID >= m_nNumTextures)
		return NULL;
	return m_Textures[TexID].pData;
}


/**
 * Creates a new skin object using the given material. 
 * texture is set to NULL till a texture is added to that skin.
 * -> IN:  OYCOLOR - ambient material  color 
 *         OYCOLOR - diffuse material color 
 *         OYCOLOR - emissive material color 
 *         OYCOLOR - specular material color 
 *         float   - power for specular reflection
 * -> OUT: UINT    - ID to reference new skin
 */
HRESULT OyD3D9SkinManager::AddSkin(const OyColor *pcAmbient,
                                   const OyColor *pcDiffuse,
                                   const OyColor *pcEmissive,
                                   const OyColor *pcSpecular,
                                   float fSpecPower,
                                   UINT  *nSkinID)
{
	bool    bMatFound = false;

	// allocate (INIT_SKIN_ARRAY_NUM) new memory slots for skins if necessary
	if( (m_nNumSkins % INIT_SKIN_ARRAY_NUM) == 0 ) 
	{
		unsigned int n = m_nNumSkins + INIT_SKIN_ARRAY_NUM;
		if( !m_Skins.Resize(n) )
			return OY_OUTOFMEMORY;
	}

	OyMaterial mat;
	mat.cAmbient  = *pcAmbient;
	mat.cDiffuse  = *pcDiffuse;
	mat.cEmissive = *pcEmissive;
	mat.cSpecular = *pcSpecular;
	mat.fPower    = fSpecPower;

	UINT nMat;
	// do we already have an equal material
	for(nMat=0; nMat<m_nNumMaterials; nMat++) 
	{
		if( MaterialEqual(&mat, &m_Materials[nMat]) )
		{
			bMatFound = true;
			break;
		}
	}

	// if exists store its ID otherwise create it new
	if(bMatFound)
		m_Skins[m_nNumSkins].nMaterialID = nMat;
	else 
	{
		m_Skins[m_nNumSkins].nMaterialID = m_nNumMaterials;

		// allocate (INIT_MATERIAL_ARRAY_NUM) new memory slots for materials if necessary
		if( (m_nNumMaterials % INIT_MATERIAL_ARRAY_NUM) == 0 )
		{
			unsigned int n = m_nNumMaterials + INIT_MATERIAL_ARRAY_NUM;

			if( !m_Materials.Resize(n) ) 
				return OY_OUTOFMEMORY;
		}
		memcpy(&m_Materials[m_nNumMaterials], &mat, sizeof(OyMaterial));
		m_nNumMaterials++;
	}

	m_Skins[m_nNumSkins].bAlpha = false;
	m_Skins[m_nNumSkins].bAlphaTest = false;
	m_Skins[m_nNumSkins].nPrimitiveType = 4;
	for(int i=0; i<8; i++) 
		m_Skins[m_nNumSkins].nTextureID[i] = 0xFFFFFFFF;

	// save ID and add to count
	(*nSkinID) = m_nNumSkins;
	m_nNumSkins++;

	return OY_OK;
}

void OyD3D9SkinManager::SetAlphaToSkin(UINT nSkinID, bool bAlpha)
{
	if(nSkinID >= m_nNumSkins)
		return;
	m_Skins[nSkinID].bAlpha = bAlpha;
}

void OyD3D9SkinManager::SetAlphaTestToSkin(UINT nSkinID, bool bAlphaTest)
{
	if(nSkinID >= m_nNumSkins)
		return;
	m_Skins[nSkinID].bAlphaTest = bAlphaTest;
}

void OyD3D9SkinManager::SetPrimitiveTypeToSkin(UINT nSkinID, char PrimitiveType)
{
	if(nSkinID >= m_nNumSkins)
		return;
	m_Skins[nSkinID].nPrimitiveType = PrimitiveType;
}

/**
 * Add a texture to a given skin. 
 * -> IN: UINT      - ID of skin to receive texture
 *        char*     - name of file used as texture
 *		  slot		- TextureID in 0-7
 */
HRESULT OyD3D9SkinManager::AddTexture(UINT nSkinID, const TCHAR *chName, UINT slot)
{
	//OyTexture *pOyTex = NULL;
	HRESULT hr;
	//UINT        nTex, n;
	//bool        bTexFound = false;

	// is skin ID valid at all
	if(nSkinID >= m_nNumSkins)
		return OY_INVALIDID;

	// all 8 stages for this skin already set?
	if(slot > 7)
	{
		OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: AddTexture() failed, all 8 stages set");
		return OY_BUFFERSIZE;
	}

	// if no texture name
	if(	_tcslen(chName) == 0 )
	{
		// put texture ID to skin ID
		m_Skins[nSkinID].nTextureID[slot] = 0xFFFFFFFF;	
		return OY_OK;
	}

	// do we already have this texture
	UnicodeString TexName(chName);
	HashEntry<UnicodeString, unsigned int> *pFoundEntry = m_TexNameIDMap.Find(TexName);

	UINT nFoundTexID = (pFoundEntry == 0) ? 0xFFFFFFFF : pFoundEntry->m_data;
/*
	for(nTex=0; nTex<m_nNumTextures; nTex++)
	{
		if ( strcmp(chName, m_pTextures[nTex].chName) == 0 ) {
			bTex = true;
			break;
			}
		} // for [TEXTURES]
*/
	// load new texture if not yet done
	if(nFoundTexID == 0xFFFFFFFF)
	{
		// allocate (INIT_TEXTURE_ARRAY_NUM) new memory slots for textures if necessary
		if( (m_nNumTextures % INIT_TEXTURE_ARRAY_NUM) == 0 )
		{
			unsigned int n = m_nNumTextures + INIT_TEXTURE_ARRAY_NUM;
			if( !m_Textures.Resize(n) ) 
			{
				OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: AddTexture() failed, realloc()");
				return OY_OUTOFMEMORY;
			}
		}


		// save texture name
		UINT NameLen = _tcslen(chName);
		m_Textures[m_nNumTextures].chName = new TCHAR[NameLen+1];
		_tcscpy_s(m_Textures[m_nNumTextures].chName, NameLen+1, chName);
		//memcpy(m_Textures[m_nNumTextures].chName, chName, _tcslen(chName)+1);

		// create d3d texture from that pointer
		hr = CreateTexture(&m_Textures[m_nNumTextures]);
		if(FAILED(hr))
		{
			delete [] m_Textures[m_nNumTextures].chName;
			m_Textures[m_nNumTextures].chName = NULL;
			OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: CreateTexture() failed");
			return hr;
		}

		// save ID and add to count
		nFoundTexID = m_nNumTextures;
		m_nNumTextures++;

		m_TexNameIDMap.Insert(TexName, nFoundTexID);
    }

	// put texture ID to skin ID
	m_Skins[nSkinID].nTextureID[slot] = nFoundTexID;
	
	return OY_OK;
}

/**
 * Add a texture to a given skin, but this is supposed to be a
 * heightmap that should be recalculated as normal map needed
 * to perform bump mapping. 
 */
HRESULT OyD3D9SkinManager::AddTextureHeightmapAsBump(UINT nSkinID, const TCHAR *chName, UINT slot) 
{
	//OyTexture *pOyTex = NULL;
	HRESULT     hr;
	//UINT        nTex, n;
	//bool        bTex=false;

	// is skin ID valid at all
	if(nSkinID >= m_nNumSkins) 
		return OY_INVALIDID;

	// all 8 stages for this skin already set?
	if(slot > 7)
	{
		OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: AddTexture() failed, all 8 stages set");
		return OY_BUFFERSIZE;
	}

	// do we already have this texture
	UnicodeString TexName(chName);
	HashEntry<UnicodeString, unsigned int> *pFoundEntry = m_TexNameIDMap.Find(TexName);

	UINT nFoundTexID = (pFoundEntry == 0) ? 0xFFFFFFFF : pFoundEntry->m_data;
/*
   for(nTex=0; nTex<m_nNumTextures; nTex++)
   {
      if ( strcmp(chName, m_pTextures[nTex].chName) == 0 ) {
         bTex = true;
         break;
         }
      } // for [TEXTURES]
*/
	// load new texture if not yet done
	if(nFoundTexID == 0xFFFFFFFF)
	{
		// allocate (INIT_TEXTURE_ARRAY_NUM) new memory slots for textures if necessary
		if( (m_nNumTextures % INIT_TEXTURE_ARRAY_NUM) == 0 )
		{
			unsigned int n = m_nNumTextures + INIT_TEXTURE_ARRAY_NUM;
			
			if( !m_Textures.Resize(n) ) 
			{
				OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: AddTexture() failed, realloc()");
				return OY_OUTOFMEMORY;
			}
		}

		// save texture name
		m_Textures[m_nNumTextures].chName = new TCHAR[_tcslen(chName)+1];
		memcpy(m_Textures[m_nNumTextures].chName, chName, _tcslen(chName)+1);

		// create d3d texture from that pointer
		hr = CreateTexture(&m_Textures[m_nNumTextures]);
		if(FAILED(hr)) 
		{
			OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: CreateTexture() failed");
			return hr;
		}

		// build normals from heightvalues
		hr = ConvertToNormalmap( &m_Textures[m_nNumTextures] );
		if(FAILED(hr))
		{
			OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: ConvertToNormalmap() failed");
			return hr;
		}

		// save ID and add to count
		nFoundTexID = m_nNumTextures;
		m_nNumTextures++;

		m_TexNameIDMap.Insert(TexName, nFoundTexID);
	} // load texture

	// put texture ID to skin ID
	m_Skins[nSkinID].nTextureID[slot] = nFoundTexID;

	return OY_OK;
}

// encode vector data as RGBA color value for normal map
DWORD VectortoRGBA(OyVector4D *vc, float fHeight)
{
	DWORD r = (DWORD)( 127.0f * vc->x + 128.0f );
	DWORD g = (DWORD)( 127.0f * vc->y + 128.0f );
	DWORD b = (DWORD)( 127.0f * vc->z + 128.0f );
	DWORD a = (DWORD)( 255.0f * fHeight );
	return( (a<<24L) + (r<<16L) + (g<<8L) + (b<<0L) );
}

/**
 * Suppose the texture is 32 Bit format heightmap and needs to be
 * converted to be a normal map instead.
 */
HRESULT OyD3D9SkinManager::ConvertToNormalmap(OyTexture *pTexture) 
{
	HRESULT hr = OY_OK;

	D3DLOCKED_RECT  d3dRect;
	D3DSURFACE_DESC desc;
   
	// get a dummy pointer
	LPDIRECT3DTEXTURE9 pTex = ((LPDIRECT3DTEXTURE9)pTexture->pData);

	pTex->GetLevelDesc(0, &desc);

	if( FAILED(pTex->LockRect(0, &d3dRect, NULL, 0)) )
	{
		_stprintf_s( m_ErrorString, L"error: cannot LockRect() of Texture \"%s\"", pTexture->chName );
		OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, m_ErrorString);

		return OY_BUFFERLOCK;
	}

	// get pointer to pixel data
	DWORD* pPixel = (DWORD*)d3dRect.pBits;
   
	// build normals at each pixel
	for(DWORD j=0; j<desc.Height; j++) 
	{
		for(DWORD i=0; i<desc.Width; i++) 
		{
			DWORD color00 = pPixel[0];
			DWORD color10 = pPixel[1];
			DWORD color01 = pPixel[d3dRect.Pitch/sizeof(DWORD)];
         
			float fHeight00 = (float)((color00 & 0x00ff0000)>>16)/255.0f;
			float fHeight10 = (float)((color10 & 0x00ff0000)>>16)/255.0f;
			float fHeight01 = (float)((color01 & 0x00ff0000)>>16)/255.0f;
         
			OyVector4D vcPoint00( i+0.0f, j+0.0f, fHeight00 );
			OyVector4D vcPoint10( i+1.0f, j+0.0f, fHeight10 );
			OyVector4D vcPoint01( i+0.0f, j+1.0f, fHeight01 );
			OyVector4D vc10 = vcPoint10 - vcPoint00;
			OyVector4D vc01 = vcPoint01 - vcPoint00;
         
			OyVector4D vcNormal;
			vcNormal.Cross(vc10, vc01);
			vcNormal.Normalize();
         
			// store normal as RGBA in normalmap
			*pPixel++ = VectortoRGBA( &vcNormal, fHeight00 );
		}
	}
	pTex->UnlockRect(0);
   
//LPDIRECT3DSURFACE9 pSurface=NULL;
//pTex->GetSurfaceLevel(0, &pSurface);
//D3DXSaveSurfaceToFile("normal.bmp", D3DXIFF_BMP, pSurface, NULL, NULL);

	return OY_OK;
}

/**
 * Creates a d3dtexture object and loads the image data from disc.
 * -> IN: OyTexture - reference to texture object to store data
 */
HRESULT OyD3D9SkinManager::CreateTexture(OyTexture *pTexture)
{
	D3DLOCKED_RECT		d3dRect;
	D3DFORMAT			fmt;
	HRESULT				hr;
	int					LineWidth;
	void				*pMemory = NULL;
	FIBITMAP			*dib = NULL;

	FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeU(pTexture->chName);
	dib = FreeImage_LoadU(fif, pTexture->chName, 0);

	// D3D Up-Left is (0,0), BitMap need Flip Vertical
	FreeImage_FlipVertical(dib); 

	if(!dib)
	{
		_stprintf_s( m_ErrorString, L"error: cannot open texture \"%s\"", pTexture->chName );
		OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, m_ErrorString);
		return OY_FILENOTFOUND;
	}

	FREE_IMAGE_TYPE fit = FreeImage_GetImageType(dib);
	if( fit == FIT_BITMAP )
	{
		unsigned int bpp = FreeImage_GetBPP(dib);
		if( bpp == 32 )	
			fmt = D3DFMT_A8R8G8B8;
		else if( bpp == 24 ) 
			fmt = D3DFMT_X8R8G8B8;
		else if( bpp == 8 )
		{
			FIBITMAP* temp = dib;
			dib = FreeImage_ConvertTo32Bits(dib);
			FreeImage_Unload(temp);
			fmt = D3DFMT_A8R8G8B8;
		}
		else
		{
			FreeImage_Unload(dib);
			return OY_INVALIDFILE;
		}
	}
	else
	{
		_stprintf_s( m_ErrorString, L"error: texture is not 24 bit \"%s\"", pTexture->chName );
		OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, m_ErrorString);

		FreeImage_Unload(dib);
		return OY_INVALIDFILE;
	}

	unsigned int lwidth = FreeImage_GetWidth(dib);
	unsigned int lheight = FreeImage_GetHeight(dib);
	unsigned int lpitch  = FreeImage_GetPitch(dib);

	// build d3d texture object
	hr = m_pDevice->CreateTexture(lwidth, lheight, 1, 0,
									fmt, D3DPOOL_MANAGED,
									(LPDIRECT3DTEXTURE9*)(&(pTexture->pData)),
									NULL);
	if(FAILED(hr))
	{
		//if(hr==D3DERR_INVALIDCALL)
		//	Log("error: IDirect3DDevice::CreateTexture failed (D3DERR_INVALIDCALL)");
		//else if(hr==D3DERR_OUTOFVIDEOMEMORY)
		//	Log("error: IDirect3DDevice::CreateTexture failed (D3DERR_OUTOFVIDEOMEMORY)");
		//else if(hr==E_OUTOFMEMORY)
		//	Log("error: IDirect3DDevice::CreateTexture failed (E_OUTOFMEMORY)");
		//else if(hr==D3DOK_NOAUTOGEN)
		//	Log("error: IDirect3DDevice::CreateTexture failed (D3DOK_NOAUTOGEN)");
		//else
		//	Log("error: IDirect3DDevice::CreateTexture failed (unknown)");
		
		OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: IDirect3DDevice::CreateTexture failed");

		FreeImage_Unload(dib);
		return OY_FAIL;
	}

	// get a dummy pointer
	LPDIRECT3DTEXTURE9 pTex = ((LPDIRECT3DTEXTURE9)pTexture->pData);

	if( FAILED(pTex->LockRect(0, &d3dRect, NULL, 0)) )
	{
		_stprintf_s( m_ErrorString, L"error: cannot lock texture to copy pixels \"%s\"", pTexture->chName );
		OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, m_ErrorString);
		FreeImage_Unload(dib);
		return OY_BUFFERLOCK;
	}

	if( fmt == D3DFMT_A8R8G8B8 )
	{
		LineWidth = d3dRect.Pitch >> 2;		// 32 bit = 4 byte
		pMemory = (DWORD*)d3dRect.pBits;

		BYTE *bits = (BYTE*)FreeImage_GetBits(dib);
		for(UINT y = 0; y < lheight; y++) 
		{
			BYTE *pixel = (BYTE*)bits;
			for(UINT x = 0; x < lwidth; x++)
			{
				((DWORD*)pMemory)[x + (y*LineWidth)] = 
					D3DCOLOR_ARGB(pixel[FI_RGBA_ALPHA], pixel[FI_RGBA_RED], pixel[FI_RGBA_GREEN], pixel[FI_RGBA_BLUE]);
				pixel += 4;
			}
			// next line
			bits += lpitch;
		}
	}
	else
	{
		LineWidth = d3dRect.Pitch >> 2;		// 32 bit = 4 byte
		pMemory = (BYTE*)d3dRect.pBits;

		BYTE *bits = (BYTE*)FreeImage_GetBits(dib);
		for(UINT y = 0; y < lheight; y++) 
		{
			BYTE *pixel = (BYTE*)bits;
			for(UINT x = 0; x < lwidth; x++)
			{
				((DWORD*)pMemory)[x + (y*LineWidth)] = 
					D3DCOLOR_ARGB(255, pixel[FI_RGBA_RED], pixel[FI_RGBA_GREEN], pixel[FI_RGBA_BLUE]);

				pixel += 3;
			}
			// next line
			bits += lpitch;
		}
	}

	pTex->UnlockRect(0);

	FreeImage_Unload(dib);
	return OY_OK;
}

/**
 * get info of texture in disk. 
 * -> IN: 
 *				chName*			- name of texture file in disk
 * -> IN/OUT:	width height	- Texture width and height
 *				numBytesOfData  - number of bytes of texture
 *				bits			- color bits
 * -> OUT:		bool			- load texture succeed?
 */

bool OyD3D9SkinManager::GetTextureInfo(const TCHAR *chName, UINT& width, UINT& height, UINT& bits)
{
	FIBITMAP *dib = NULL;
	FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeU(chName);
	dib = FreeImage_LoadU(fif, chName, 0);

	if(!dib)
		return false;

	FREE_IMAGE_TYPE fit = FreeImage_GetImageType(dib);
	if( fit == FIT_BITMAP )
	{
		unsigned int bpp = FreeImage_GetBPP(dib);
		if( bpp == 32 )	
			bits = 32;
		else if( bpp == 24 ) 
			bits = 24;
		else if( bpp == 8 )
			bits = 32;
		else
		{
			FreeImage_Unload(dib);
			return false;
		}
	}
	else
	{
		FreeImage_Unload(dib);
		return false;
	}

	width = FreeImage_GetWidth(dib);
	height = FreeImage_GetHeight(dib);


	FreeImage_Unload(dib);
	return true;
}

bool OyD3D9SkinManager::LoadTextureData(const TCHAR *chName, void *rawData)
{
	FIBITMAP *dib = NULL;

	FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeU(chName);
	dib = FreeImage_LoadU(fif, chName, 0);

	if(!dib)
		return false;

	// D3D Up-Left is (0,0), BitMap need Flip Vertical
	FreeImage_FlipVertical(dib); 

	unsigned int bpp = FreeImage_GetBPP(dib);
	if( bpp == 8 )
	{
		FIBITMAP* temp = dib;
		dib = FreeImage_ConvertTo32Bits(dib);
		FreeImage_Unload(temp);
		bpp = 32;
	}


	unsigned int lwidth = FreeImage_GetWidth(dib);
	unsigned int lheight = FreeImage_GetHeight(dib);
	unsigned int lpitch  = FreeImage_GetPitch(dib);

	BYTE *bits = (BYTE*)FreeImage_GetBits(dib);

	memcpy(rawData, bits, lwidth*lheight*bpp/8);

	FreeImage_Unload(dib);
	return true;
}

HRESULT	OyD3D9SkinManager::AddDeferedTexture(UINT nSkinID, const TCHAR *chName, UINT slot)
{
	static DLTexture newTex;
	newTex.m_skinID = nSkinID;
	_tcscpy_s(newTex.m_filename, chName);
	newTex.m_slot = slot;


	DoubleListIterator<RingFIFO<DLTexture>*> it = m_SyncLoadTextureList.GetIterator();
	while( it.Valid() )
	{
		if( it.Item()->getFreeSize() != 0 )
		{
			it.Item()->push(&newTex, 1);
			return OY_OK;
		}
		it.Forth();
	}

	// All Ring Buffer is full, new one new Buffer
	RingFIFO<DLTexture> *p = new RingFIFO<DLTexture>(INIT_SYNC_TEXTURE_RESOURCE);
	p->push(&newTex, 1);
	m_SyncLoadTextureList.Append( p ); 


	return OY_OK;
}

void OyD3D9SkinManager::DeferedSyncResource()
{
	static DLTexture newTex;

	DoubleListIterator<RingFIFO<DLTexture>*> it = m_SyncLoadTextureList.GetIterator();
	while( it.Valid() )
	{
		while( it.Item()->pop(&newTex, 1) != 0 )
		{
			AddTexture(newTex.m_skinID, newTex.m_filename, newTex.m_slot);
		}
		it.Item()->clear();
		it.Forth();
	}
}

